package tt.dz.biz.service.account;

import java.math.BigDecimal;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
import tt.dz.biz.dao.account.AccountingDAO;
import tt.dz.biz.dao.financial.MerchantDAO;
import tt.dz.common.AppContxtUtil;
import tt.dz.common.BigDecimalUtil;
import tt.dz.common.BusinessException;
import tt.dz.common.DzConstants;
import tt.dz.common.DzConstants.borrowOrLoanFlag;
import tt.dz.common.DzConstants.isSelfMerchant;
import tt.dz.common.DzConstants.realTime;
import tt.dz.common.DzConstants.subjectType;
import tt.dz.common.DzConstants.userType;
import tt.dz.common.LogUtil;
import tt.dz.vo.AccountingRuleVO;
import tt.dz.vo.MerchAccountDividendVO;
import tt.dz.vo.MerchantSubjectAccVO;
import tt.dz.vo.MerchantVO;
import tt.dz.vo.TranInfoVO;
import tt.dz.vo.TranSubVO;
import tt.dz.vo.UserBaseVO;

public class MerchantToMerchantPOJO
  extends AccountDividendPOJO
{
  MerchantDAO merchantDAO = null;
  private String payer;
  private String receiver;
  
  public MerchantToMerchantPOJO() {}
  
  public MerchantToMerchantPOJO(TranInfoVO tranInfoVO)
    throws Exception
  {
    super(tranInfoVO);
    init();
  }
  
  private MerchantToMerchantPOJO init()
    throws Exception
  {
    if ((this.isRealTime) && (StringUtils.isBlank(this.bankSubjectCode))) {
      throw new Exception("初始化运营商到运营商转账对象失败，原因：实时转账时银行存款下二级科目未找到");
    }
    this.payer = this.tranInfoVO.getPayer();
    if (null != this.tranInfoVO.getReceiver()) {
      this.receiver = this.tranInfoVO.getReceiver();
    } else {
      this.receiver = ((TranSubVO)this.tranInfoVO.getTranSubVOList().get(0)).getReceiver();
    }
    this.merchantDAO = ((MerchantDAO)AppContxtUtil.getBean("merchantDAO"));
    
    return this;
  }
  
  private MerchantToMerchantPOJO addPayerTotalAccount()
    throws Exception
  {
    try
    {
      MerchantVO merchant = this.merchantDAO.queryMerchantByCode(this.payer);
      if (!DzConstants.isSelfMerchant.SELF.value().equals(merchant.getIsSelf())) {
        return this;
      }
      if (this.isRealTime)
      {
        AccountingRuleVO rule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO.getServiceNo(), DzConstants.subjectType.LIABILITIES
          .value(), DzConstants.realTime.YES.value());
        MerchAccountDividendVO totalDividend = new MerchAccountDividendVO();
        MerchantSubjectAccVO mertchSubject = new MerchantSubjectAccVO();
        totalDividend.setSubjectCode(rule.getSubjectCode());
        totalDividend.setSubSubjectCode(rule.getSubSubjectCode());
        totalDividend.setMerchantCode(this.payer);
        totalDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        totalDividend.setTradeNo(this.tranInfoVO.getTradeNo());
        totalDividend.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
        totalDividend.setAccountingDate(this.accountingDate);
        totalDividend.setMerchantCode1(this.receiver);
        
        mertchSubject.setMerchantCode(totalDividend.getMerchantCode());
        mertchSubject.setSubSubjectCode(totalDividend.getSubSubjectCode());
        mertchSubject.setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), totalDividend.getAmount()));
        this.merchAccountDividendList.add(totalDividend);
        this.merchantSubjectList.add(mertchSubject);
        
        MerchAccountDividendVO bankSubjectDividend = new MerchAccountDividendVO();
        MerchantSubjectAccVO bankSubjectAccount = new MerchantSubjectAccVO();
        bankSubjectDividend.setSubSubjectCode(this.bankSubjectCode);
        bankSubjectDividend.setMerchantCode(this.payer);
        bankSubjectDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        bankSubjectDividend.setTradeNo(this.tranInfoVO.getTradeNo());
        bankSubjectDividend.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
        bankSubjectDividend.setAccountingDate(this.accountingDate);
        bankSubjectDividend.setMerchantCode1(this.receiver);
        
        bankSubjectAccount.setMerchantCode(bankSubjectDividend.getMerchantCode());
        bankSubjectAccount.setSubSubjectCode(bankSubjectDividend.getSubSubjectCode());
        bankSubjectAccount
          .setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), bankSubjectDividend.getAmount()));
        this.merchAccountDividendList.add(bankSubjectDividend);
        this.merchantSubjectList.add(bankSubjectAccount);
      }
      else
      {
        LogUtil.error("业务场景错误，运营商间结算业务，但是出现了非及时到账的情况。");
      }
    }
    catch (Exception e)
    {
      LogUtil.error("处理支付方总金额账户和分录失败", e);
      throw e;
    }
    return this;
  }
  
  private MerchantToMerchantPOJO addReceiverTotalAccount()
    throws Exception
  {
    try
    {
      if (this.isRealTime)
      {
        AccountingRuleVO rule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO.getServiceNo(), DzConstants.subjectType.ASSETS
          .value(), DzConstants.realTime.YES.value());
        MerchAccountDividendVO totalDividend = new MerchAccountDividendVO();
        MerchantSubjectAccVO mertchSubject = new MerchantSubjectAccVO();
        totalDividend.setSubjectCode(rule.getSubjectCode());
        totalDividend.setSubSubjectCode(rule.getSubSubjectCode());
        totalDividend.setMerchantCode(this.receiver);
        totalDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        totalDividend.setTradeNo(this.tranInfoVO.getTradeNo());
        totalDividend.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
        totalDividend.setAccountingDate(this.accountingDate);
        totalDividend.setMerchantCode1(this.payer);
        
        mertchSubject.setMerchantCode(totalDividend.getMerchantCode());
        mertchSubject.setSubSubjectCode(totalDividend.getSubSubjectCode());
        mertchSubject.setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), totalDividend.getAmount()));
        this.merchAccountDividendList.add(totalDividend);
        this.merchantSubjectList.add(mertchSubject);
        
        MerchAccountDividendVO bankSubjectDividend = new MerchAccountDividendVO();
        MerchantSubjectAccVO bankSubjectAccount = new MerchantSubjectAccVO();
        bankSubjectDividend.setSubSubjectCode(this.bankSubjectCode);
        bankSubjectDividend.setMerchantCode(this.receiver);
        bankSubjectDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        bankSubjectDividend.setTradeNo(this.tranInfoVO.getTradeNo());
        bankSubjectDividend.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
        bankSubjectDividend.setAccountingDate(this.accountingDate);
        bankSubjectDividend.setMerchantCode1(this.payer);
        
        bankSubjectAccount.setMerchantCode(bankSubjectDividend.getMerchantCode());
        bankSubjectAccount.setSubSubjectCode(bankSubjectDividend.getSubSubjectCode());
        bankSubjectAccount.setAcctBal(bankSubjectDividend.getAmount());
        this.merchAccountDividendList.add(bankSubjectDividend);
        this.merchantSubjectList.add(bankSubjectAccount);
      }
      else
      {
        LogUtil.error("业务场景错误，运营商间结算业务，但是出现了非及时到账的情况。");
      }
    }
    catch (Exception e)
    {
      LogUtil.error("处理收款方总金额账户和分录失败", e);
      throw e;
    }
    return this;
  }
  
  public void saveAccountDividend()
    throws Exception
  {
    init().addPayerTotalAccount().addReceiverTotalAccount();
    if (CollectionUtils.isEmpty(this.merchAccountDividendList)) {
      throw new BusinessException("分录数据为空，请检查业务逻辑。");
    }
    this.merchAccountDividendList = mergeMerchAccountDividend(this.merchAccountDividendList);
    int[] cnt = this.accountingDAO.insertMerchAccountDividend(this.merchAccountDividendList);
    judgeResult(cnt, "运营商对运营商结算插入账户分录失败，参数为merchAccountDividendList：" + this.merchAccountDividendList);
    recoverEntUserBal();
  }
  
  private void recoverEntUserBal()
  {
    try
    {
      List<UserBaseVO> userList = this.accountingDAO.queryUserByMerchCode(this.tranInfoVO.getOriginalPayer());
      for (UserBaseVO userBaseVO : userList) {
        if (DzConstants.userType.ENTERPRISE_CUSTOMER.value().equals(userBaseVO.getUserType()))
        {
          userBaseVO.setBalance(this.tranInfoVO.getPaymentAmount());
          this.accountingDAO.updateEntUserBal(userBaseVO);
        }
      }
    }
    catch (Exception e)
    {
      LogUtil.error(
        "恢复企业客户的剩余额度异常，运营商代码为：" + this.tranInfoVO.getOriginalPayer() + ",恢复的额度为：" + this.tranInfoVO.getPaymentAmount(), e);
    }
  }
}
